package cn.jervain.nut.auth.starter;

import cn.jervain.nut.auth.core.AuthFilter;
import cn.jervain.nut.auth.core.encoder.PasswordEncoder;
import cn.jervain.nut.auth.core.encoder.bcrypt.BCryptPasswordEncoder;
import cn.jervain.nut.auth.core.provider.AuthProvider;
import cn.jervain.nut.auth.core.provider.InMemoryAuthProvider;
import cn.jervain.nut.auth.core.storage.InMemoryTokenStorage;
import cn.jervain.nut.auth.core.storage.RedisTokenStorage;
import cn.jervain.nut.auth.core.storage.TokenStorage;
import cn.jervain.nut.auth.starter.properties.AuthProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@EnableConfigurationProperties(value = {AuthProperty.class})
@Configuration
public class AutoConfiguration implements WebMvcConfigurer {

    @Autowired
    private AuthProperty authProperty;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authFilter());
    }

    @Bean
    @ConditionalOnMissingBean
    public AuthProvider<Object> authProvider() {
        return new InMemoryAuthProvider(
                authProperty.getUsernameParam(),
                authProperty.getPasswordParam(),
                authProperty.getAuthEndpoint(),
                authProperty.getAuthMethod(),
                authProperty.getMemory().getUsername(),
                authProperty.getMemory().getPassword()
        );
    }

    @Bean
    @ConditionalOnProperty(prefix = "nut.auth", name = "demo", havingValue = "true")
    public AuthProvider<Object> demoAuthProvider() {
        return new InMemoryAuthProvider(
                authProperty.getUsernameParam(),
                authProperty.getPasswordParam(),
                authProperty.getAuthEndpoint(),
                authProperty.getAuthMethod(),
                authProperty.getMemory().getUsername(),
                authProperty.getMemory().getPassword()
        );
    }


    @Bean
    @ConditionalOnMissingBean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @ConditionalOnMissingBean
    public AuthFilter authFilter() {
        return new AuthFilter(
                authProperty.getPermits(),
                authProperty.getTokenKey(),
                authProperty.getTokenPrefix()
        );
    }

    @Bean
    @ConditionalOnProperty(prefix = "nut.auth", name = "demo", havingValue = "false")
    @ConditionalOnMissingBean
    public TokenStorage<Object> tokenStorage() {
        return new RedisTokenStorage<>();
    }

    @Bean
    @ConditionalOnProperty(prefix = "nut.auth", name = "demo", havingValue = "true")
    @ConditionalOnMissingBean
    public TokenStorage<Object> demoTokenStorage() {
        return new InMemoryTokenStorage<>();
    }

}
